import { Control } from './Control';
import * as DomUtil from '../dom/DomUtil';

/*
 * @class Control.Scale
 * @aka L.Control.Scale
 * @inherits Control
 *
 * A simple scale control that shows the scale of the current center of screen in metric (m/km) and imperial (mi/ft) systems. Extends `Control`.
 *
 * @example
 *
 * ```js
 * L.control.scale().addTo(map);
 * ```
 */

export var Scale = Control.extend({
  // @section
  // @aka Control.Scale options
  options: {
    position: 'bottomleft',

    // @option maxWidth: Number = 100
    // Maximum width of the control in pixels. The width is set dynamically to show round values (e.g. 100, 200, 500).
    maxWidth: 100,

    // @option metric: Boolean = True
    // Whether to show the metric scale line (m/km).
    metric: true,

    // @option imperial: Boolean = True
    // Whether to show the imperial scale line (mi/ft).
    imperial: true,

    // @option updateWhenIdle: Boolean = false
    // If `true`, the control is updated on [`moveend`](#map-moveend), otherwise it's always up-to-date (updated on [`move`](#map-move)).
  },

  onAdd: function (map) {
    var className = 'leaflet-control-scale',
      container = DomUtil.create('div', className),
      options = this.options;

    this._addScales(options, className + '-line', container);

    map.on(options.updateWhenIdle ? 'moveend' : 'move', this._update, this);
    map.whenReady(this._update, this);

    return container;
  },

  onRemove: function (map) {
    map.off(
      this.options.updateWhenIdle ? 'moveend' : 'move',
      this._update,
      this,
    );
  },

  _addScales: function (options, className, container) {
    if (options.metric) {
      this._mScale = DomUtil.create('div', className, container);
    }
    if (options.imperial) {
      this._iScale = DomUtil.create('div', className, container);
    }
  },

  _update: function () {
    var map = this._map,
      y = map.getSize().y / 2;

    var maxMeters = map.distance(
      map.containerPointToLatLng([0, y]),
      map.containerPointToLatLng([this.options.maxWidth, y]),
    );

    this._updateScales(maxMeters);
  },

  _updateScales: function (maxMeters) {
    if (this.options.metric && maxMeters) {
      this._updateMetric(maxMeters);
    }
    if (this.options.imperial && maxMeters) {
      this._updateImperial(maxMeters);
    }
  },

  _updateMetric: function (maxMeters) {
    var meters = this._getRoundNum(maxMeters),
      label = meters < 1000 ? meters + ' m' : meters / 1000 + ' km';

    this._updateScale(this._mScale, label, meters / maxMeters);
  },

  _updateImperial: function (maxMeters) {
    var maxFeet = maxMeters * 3.2808399,
      maxMiles,
      miles,
      feet;

    if (maxFeet > 5280) {
      maxMiles = maxFeet / 5280;
      miles = this._getRoundNum(maxMiles);
      this._updateScale(this._iScale, miles + ' mi', miles / maxMiles);
    } else {
      feet = this._getRoundNum(maxFeet);
      this._updateScale(this._iScale, feet + ' ft', feet / maxFeet);
    }
  },

  _updateScale: function (scale, text, ratio) {
    scale.style.width = Math.round(this.options.maxWidth * ratio) + 'px';
    scale.innerHTML = text;
  },

  _getRoundNum: function (num) {
    var pow10 = Math.pow(10, (Math.floor(num) + '').length - 1),
      d = num / pow10;

    d = d >= 10 ? 10 : d >= 5 ? 5 : d >= 3 ? 3 : d >= 2 ? 2 : 1;

    return pow10 * d;
  },
});

// @factory L.control.scale(options?: Control.Scale options)
// Creates an scale control with the given options.
export var scale = function (options) {
  return new Scale(options);
};
